package com.symaster.gameengine.e2d;

import com.symaster.gameengine.core.Canvas;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWFramebufferSizeCallback;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;

/**
 * 场景Canvas
 *
 * @author yinmiao
 * @version 2023/11/15
 */
public class SceneCanvas extends Canvas {
    private Scene scene;
    private int width;
    private int height;

    public Scene getScene() {
        return scene;
    }

    public void setScene(Scene scene) {
        this.scene = scene;
    }

    @Override
    public void loop(long window, int initWindowWidth, int initWindowHeight) {
        this.width = initWindowWidth;
        this.height = initWindowHeight;

        if (this.scene == null) {
            throw new IllegalStateException("scene not set");
        }

        scene.setWindow(window);

        // 初始化场景Fbo缓冲区
        this.setupSceneFboBuffer(window);

        while (!GLFW.glfwWindowShouldClose(window)) {
            // 记录帧开始时间
            double startTime = GLFW.glfwGetTime();
            // 设置场景的宽高比
            scene.setAspectRatio(getEngineFrame().getAspectRatio());
            // 场景绘制
            scene.repaint2Fbo();
            // 绑定到默认缓冲区
            this.bindDefaultBuffer();
            // 设置canvas视口大小
            this.canvasViewport();
            // 清空
            this.clear();
            // 绘制场景FBO
            scene.renderTextureToScreen();
            // 下一帧
            this.nextFrame(window, startTime);
        }
    }

    private void clear() {
        GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
    }

    private void canvasViewport() {
        float hFloat = getWidth() / getEngineFrame().getAspectRatio();
        float yOffset = (getHeight() - hFloat) / 2f;

        // 设置窗口视口大小
        GL11.glViewport(0, Math.round(yOffset), getWidth(), Math.round(hFloat));
    }

    private void setupSceneFboBuffer(long window) {
        this.updateSceneFbo();

        // 设置窗口大小改变时的回调函数
        GLFWFramebufferSizeCallback glfwFramebufferSizeCallback = GLFW.glfwSetFramebufferSizeCallback(window, (win, w, h) -> {
            this.width = w;
            this.height = h;

            // 调整 FBO 大小
            this.updateSceneFbo();
        });

        if (glfwFramebufferSizeCallback != null) {
            glfwFramebufferSizeCallback.close();
        }
    }

    private void updateSceneFbo() {
        scene.setupFBO(getWidth(), Math.round(getWidth() / getEngineFrame().getAspectRatio()));
    }

    private int getWidth() {
        return width;
    }

    private int getHeight() {
        return height;
    }

    private void bindDefaultBuffer() {
        // 绑定到默认缓冲区
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
    }

    private void renderScene() {
        // 绘制一个应用纹理的四边形
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex2f(-1f, -1f); // 左下角
        GL11.glTexCoord2f(1, 0);
        GL11.glVertex2f(1f, -1f); // 右下角
        GL11.glTexCoord2f(1, 1);
        GL11.glVertex2f(1f, 1f); // 右上角
        GL11.glTexCoord2f(0, 1);
        GL11.glVertex2f(-1f, 1f); // 左上角
        GL11.glEnd();
    }

    @Override
    public void resourceLoad() {
        scene.resourceLoad();
    }
}
